}
}
+ pub fn is_dylib(&self) -> bool {
+ match self.kind {
+ TargetKind::Lib(ref libs) => libs.iter().any(|l| *l == LibKind::Dylib),
+ _ => false
+ }
+ }
+
pub fn linkable(&self) -> bool {
match self.kind {
TargetKind::Lib(ref kinds) => {
try!(rm_rf(&layout.proxy().fingerprint(&unit.pkg)));
try!(rm_rf(&layout.build(&unit.pkg)));
- let root = cx.out_dir(&unit);
- for (filename, _) in try!(cx.target_filenames(&unit)) {
- try!(rm_rf(&root.join(&filename)));
+ for (src, link_dst, _) in try!(cx.target_filenames(&unit)) {
+ try!(rm_rf(&src));
+ if let Some(dst) = link_dst {
+ try!(rm_rf(&dst));
+ }
}
}
/// Get the metadata for a target in a specific profile
pub fn target_metadata(&self, unit: &Unit) -> Option<Metadata> {
- let metadata = unit.target.metadata();
+ // No metadata for dylibs because of a couple issues
+ // - OSX encodes the dylib name in the executable
+ // - Windows rustc multiple files of which we can't easily link all of them
+ if !unit.profile.test && unit.target.is_dylib() {
+ return None;
+ }
+
+ let metadata = unit.target.metadata().cloned().map(|mut m| {
+ if let Some(features) = self.resolve.features(unit.pkg.package_id()) {
+ let mut feat_vec: Vec<&String> = features.iter().collect();
+ feat_vec.sort();
+ for feat in feat_vec {
+ m.mix(feat);
+ }
+ }
+ m.mix(unit.profile);
+ m
+ });
+ let mut pkg_metadata = {
+ let mut m = unit.pkg.generate_metadata();
+ if let Some(features) = self.resolve.features(unit.pkg.package_id()) {
+ let mut feat_vec: Vec<&String> = features.iter().collect();
+ feat_vec.sort();
+ for feat in feat_vec {
+ m.mix(feat);
+ }
+ }
+ m.mix(unit.profile);
+ m
+ };
+
if unit.target.is_lib() && unit.profile.test {
// Libs and their tests are built in parallel, so we need to make
// sure that their metadata is different.
- metadata.cloned().map(|mut m| {
+ metadata.map(|mut m| {
m.mix(&"test");
m
})
// Make sure that the name of this test executable doesn't
// conflict with a library that has the same name and is
// being tested
- let mut metadata = unit.pkg.generate_metadata();
- metadata.mix(&format!("bin-{}", unit.target.name()));
- Some(metadata)
+ pkg_metadata.mix(&format!("bin-{}", unit.target.name()));
+ Some(pkg_metadata)
} else if unit.pkg.package_id().source_id().is_path() &&
!unit.profile.test {
- // If we're not building a unit test but we're building a path
- // dependency, then we're likely compiling the "current package" or
- // some package in a workspace. In this situation we pass no
- // metadata by default so we'll have predictable
- // file names like `target/debug/libfoo.{a,so,rlib}` and such.
- //
- // Note, though, that the compiler's build system at least wants
- // path dependencies to have hashes in filenames. To account for
- // that we have an extra hack here which reads the
- // `__CARGO_DEFAULT_METADATA` environment variable and creates a
- // hash in the filename if that's present.
- //
- // This environment variable should not be relied on! It's basically
- // just here for rustbuild. We need a more principled method of
- // doing this eventually.
- if unit.target.is_lib() {
- env::var("__CARGO_DEFAULT_LIB_METADATA").ok().map(|meta| {
- let mut metadata = unit.pkg.generate_metadata();
- metadata.mix(&meta);
- metadata
- })
- } else {
- None
- }
+ Some(pkg_metadata)
} else {
- metadata.cloned()
+ metadata
}
}
match self.target_metadata(unit) {
Some(ref metadata) => format!("{}{}", unit.target.crate_name(),
metadata.extra_filename),
- None if unit.target.allows_underscores() => {
- unit.target.name().to_string()
+ None => self.bin_stem(unit),
+ }
+ }
+
+ fn bin_stem(&self, unit: &Unit) -> String {
+ if unit.target.allows_underscores() {
+ unit.target.name().to_string()
+ } else {
+ unit.target.crate_name()
+ }
+ }
+
+ pub fn link_stem(&self, unit: &Unit) -> Option<(PathBuf, String)> {
+ let src_dir = self.out_dir(unit);
+ let bin_stem = self.bin_stem(unit);
+ let file_stem = self.file_stem(unit);
+
+ // We currently only lift files up from the `deps` directory. If
+ // it was compiled into something like `example/` or `doc/` then
+ // we don't want to link it up.
+ if src_dir.ends_with("deps") {
+ // Don't lift up library dependencies
+ if unit.pkg.package_id() != &self.current_package && !unit.target.is_bin() {
+ None
+ } else {
+ Some((
+ src_dir.parent().unwrap().to_owned(),
+ if unit.profile.test {file_stem} else {bin_stem},
+ ))
}
- None => unit.target.crate_name(),
+ } else if bin_stem == file_stem {
+ None
+ } else if src_dir.ends_with("examples") {
+ Some((src_dir, bin_stem))
+ } else if src_dir.parent().unwrap().ends_with("build") {
+ Some((src_dir, bin_stem))
+ } else {
+ None
}
}
/// Return the filenames that the given target for the given profile will
- /// generate, along with whether you can link against that file (e.g. it's a
- /// library).
+ /// generate as a list of 3-tuples (filename, link_dst, linkable)
+ /// filename: filename rustc compiles to. (Often has metadata suffix).
+ /// link_dst: Optional file to link/copy the result to (without metadata suffix)
+ /// linkable: Whether possible to link against file (eg it's a library)
pub fn target_filenames(&self, unit: &Unit)
- -> CargoResult<Vec<(String, bool)>> {
+ -> CargoResult<Vec<(PathBuf, Option<PathBuf>, bool)>> {
+ let out_dir = self.out_dir(unit);
let stem = self.file_stem(unit);
+ let link_stem = self.link_stem(unit);
let info = if unit.target.for_host() {
&self.host_info
} else {
let crate_type = if crate_type == "lib" {"rlib"} else {crate_type};
match info.crate_types.get(crate_type) {
Some(&Some((ref prefix, ref suffix))) => {
- ret.push((format!("{}{}{}", prefix, stem, suffix),
- linkable));
+ let filename = out_dir.join(format!("{}{}{}", prefix, stem, suffix));
+ let link_dst = link_stem.clone().map(|(ld, ls)| {
+ ld.join(format!("{}{}{}", prefix, ls, suffix))
+ });
+ ret.push((filename, link_dst, linkable));
Ok(())
}
// not supported, don't worry about it
support any of the output crate types",
unit.pkg, self.target_triple());
}
+ info!("Target filenames: {:?}", ret);
Ok(ret)
}
let _p = profile::start(format!("fingerprint: {} / {}",
unit.pkg.package_id(), unit.target.name()));
let new = dir(cx, unit);
- let loc = new.join(&filename(unit));
+ let loc = new.join(&filename(cx, unit));
debug!("fingerprint at: {}", loc.display());
missing_outputs = !root.join(unit.target.crate_name())
.join("index.html").exists();
} else {
- for (filename, _) in try!(cx.target_filenames(unit)) {
- missing_outputs |= fs::metadata(root.join(filename)).is_err();
+ for (src, link_dst, _) in try!(cx.target_filenames(unit)) {
+ missing_outputs |= fs::metadata(&src).is_err();
+ if let Some(link_dst) = link_dst {
+ missing_outputs |= fs::metadata(link_dst).is_err();
+ }
}
}
/// Returns the (old, new) location for the dep info file of a target.
pub fn dep_info_loc(cx: &Context, unit: &Unit) -> PathBuf {
- dir(cx, unit).join(&format!("dep-{}", filename(unit)))
+ dir(cx, unit).join(&format!("dep-{}", filename(cx, unit)))
}
fn compare_old_fingerprint(loc: &Path, new_fingerprint: &Fingerprint)
}
}
-fn filename(unit: &Unit) -> String {
+fn filename(cx: &Context, unit: &Unit) -> String {
+ // If there exists a link stem, we have to use that since multiple target filenames
+ // may hardlink to the same target stem. If there's no link, we can use the original
+ // file_stem (which can include a suffix)
+ let file_stem = cx.link_stem(unit)
+ .map(|(_path, stem)| stem)
+ .unwrap_or_else(|| cx.file_stem(unit));
let kind = match *unit.target.kind() {
TargetKind::Lib(..) => "lib",
TargetKind::Bin => "bin",
} else {
""
};
- format!("{}{}-{}", flavor, kind, unit.target.name())
+ format!("{}{}-{}", flavor, kind, file_stem)
}
// The dep-info files emitted by the compiler all have their listed paths
} else if unit.target.is_lib() {
self.deps().to_path_buf()
} else {
- self.root().to_path_buf()
+ self.deps().to_path_buf()
}
}
.or_insert(Vec::new())
.push(("OUT_DIR".to_string(), out_dir));
- for (filename, _linkable) in try!(cx.target_filenames(unit)) {
- let dst = cx.out_dir(unit).join(filename);
+ for (dst, link_dst, _linkable) in try!(cx.target_filenames(unit)) {
+ let bindst = match link_dst {
+ Some(link_dst) => link_dst,
+ None => dst.clone(),
+ };
+
if unit.profile.test {
cx.compilation.tests.push((unit.pkg.clone(),
unit.target.name().to_string(),
dst));
} else if unit.target.is_bin() || unit.target.is_example() {
- cx.compilation.binaries.push(dst);
+ cx.compilation.binaries.push(bindst);
} else if unit.target.is_lib() {
let pkgid = unit.pkg.package_id().clone();
cx.compilation.libraries.entry(pkgid).or_insert(Vec::new())
}
let v = try!(cx.target_filenames(unit));
- let v = v.into_iter().map(|(f, _)| {
- (unit.target.clone(), cx.out_dir(unit).join(f))
+ let v = v.into_iter().map(|(f, _, _)| {
+ (unit.target.clone(), f)
}).collect::<Vec<_>>();
cx.compilation.libraries.insert(pkgid.clone(), v);
}
let do_rename = unit.target.allows_underscores() && !unit.profile.test;
let real_name = unit.target.name().to_string();
let crate_name = unit.target.crate_name();
- let move_outputs_up = unit.pkg.package_id() == &cx.current_package;
- let rustc_dep_info_loc = if do_rename {
+ // XXX(Rely on target_filenames iterator as source of truth rather than rederiving filestem)
+ let rustc_dep_info_loc = if do_rename && cx.target_metadata(unit).is_none() {
root.join(&crate_name)
} else {
root.join(&cx.file_stem(unit))
// FIXME(rust-lang/rust#18913): we probably shouldn't have to do
// this manually
- for &(ref filename, _linkable) in filenames.iter() {
- let dst = root.join(filename);
+ for &(ref dst, ref _link_dst, _linkable) in filenames.iter() {
if fs::metadata(&dst).is_ok() {
try!(fs::remove_file(&dst).chain_error(|| {
human(format!("Could not remove file: {}.", dst.display()))
}));
if do_rename && real_name != crate_name {
- let dst = root.join(&filenames[0].0);
+ let dst = &filenames[0].0;
let src = dst.with_file_name(dst.file_name().unwrap()
.to_str().unwrap()
.replace(&real_name, &crate_name));
}
if !has_custom_args || fs::metadata(&rustc_dep_info_loc).is_ok() {
+ info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc);
try!(fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_error(|| {
internal(format!("could not rename dep info: {:?}",
rustc_dep_info_loc))
// hard link our outputs out of the `deps` directory into the directory
// above. This means that `cargo build` will produce binaries in
// `target/debug` which one probably expects.
- if move_outputs_up {
- for &(ref filename, _linkable) in filenames.iter() {
- let src = root.join(filename);
- // This may have been a `cargo rustc` command which changes the
- // output, so the source may not actually exist.
- if !src.exists() {
- continue
- }
+ for (src, link_dst, _linkable) in filenames {
+ // This may have been a `cargo rustc` command which changes the
+ // output, so the source may not actually exist.
+ debug!("Thinking about linking {} to {:?}", src.display(), link_dst);
+ if !src.exists() || link_dst.is_none() {
+ continue
+ }
+ let dst = link_dst.unwrap();
- // We currently only lift files up from the `deps` directory. If
- // it was compiled into something like `example/` or `doc/` then
- // we don't want to link it up.
- let src_dir = src.parent().unwrap();
- if !src_dir.ends_with("deps") {
- continue
- }
- let dst = src_dir.parent().unwrap()
- .join(src.file_name().unwrap());
- if dst.exists() {
- try!(fs::remove_file(&dst).chain_error(|| {
- human(format!("failed to remove: {}", dst.display()))
- }));
- }
- try!(fs::hard_link(&src, &dst)
- .or_else(|_| fs::copy(&src, &dst).map(|_| ()))
- .chain_error(|| {
- human(format!("failed to link or copy `{}` to `{}`",
- src.display(), dst.display()))
+ debug!("linking {} to {}", src.display(), dst.display());
+ if dst.exists() {
+ try!(fs::remove_file(&dst).chain_error(|| {
+ human(format!("failed to remove: {}", dst.display()))
}));
}
+ try!(fs::hard_link(&src, &dst)
+ .or_else(|err| {
+ debug!("hard link failed {}. falling back to fs::copy", err);
+ fs::copy(&src, &dst).map(|_| ())
+ })
+ .chain_error(|| {
+ human(format!("failed to link or copy `{}` to `{}`",
+ src.display(), dst.display()))
+ }));
}
Ok(())
fn link_to(cmd: &mut ProcessBuilder, cx: &Context, unit: &Unit)
-> CargoResult<()> {
- for (filename, linkable) in try!(cx.target_filenames(unit)) {
+ for (dst, _link_dst, linkable) in try!(cx.target_filenames(unit)) {
if !linkable {
continue
}
v.push("=");
v.push(cx.out_dir(unit));
v.push(&path::MAIN_SEPARATOR.to_string());
- v.push(&filename);
+ v.push(&dst.file_name().unwrap());
cmd.arg("--extern").arg(&v);
}
Ok(())
execs().with_stderr(&format!("\
[COMPILING] foo v0.5.0 ({})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]foo-[..][EXE]", p.url()))
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
test bench_hello ... bench: [..] 0 ns/iter (+/- 0)
.with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]bin2-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]bin2-[..][EXE]
", dir = prj.url()))
.with_stdout("
running 1 test
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc src[/]foo.rs [..]`
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] `[..]target[/]release[/]foo-[..][EXE] hello --bench`", url = p.url()))
+[RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] hello --bench`", url = p.url()))
.with_stdout("
running 1 test
test bench_hello ... bench: [..] 0 ns/iter (+/- 0)
.with_stderr_contains(format!("\
[COMPILING] foo v0.5.0 ({})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]foo-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]
thread '[..]' panicked at 'assertion failed: \
`(left == right)` (left: \
`\"hello\"`, right: `\"nope\"`)', src[/]foo.rs:14
execs().with_stderr(&format!("\
[COMPILING] foo v0.0.1 ({})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]baz-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]baz-[..][EXE]
[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
execs().with_stderr(&format!("\
[COMPILING] foo v0.0.1 ({})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]bench-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]bench-[..][EXE]
[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
execs().with_stderr(&format!("\
[COMPILING] foo v0.0.1 ({})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]external-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]external-[..][EXE]
[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
[COMPILING] foo v0.0.1 ({})
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]release[/]foo-[..][EXE]", p.url()))
+[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
test [..] ... bench: [..] 0 ns/iter (+/- 0)
.with_stderr(&format!("\
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]bench-[..][EXE]
+[RUNNING] target[/]release[/]deps[/]bench-[..][EXE]
[RUNNING] target[/]release[/]deps[/]syntax-[..][EXE]", dir = p.url()))
.with_stdout("
running 1 test
.with_stderr(&format!("\
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] target[/]release[/]syntax-[..][EXE]", dir = p.url()))
+[RUNNING] target[/]release[/]deps[/]syntax-[..][EXE]", dir = p.url()))
.with_stdout("
running 1 test
test bench ... bench: [..] 0 ns/iter (+/- 0)
[RUNNING] [..] -C opt-level=3 [..]
[RUNNING] [..] -C opt-level=3 [..]
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] `[..]target[/]release[/]bench-[..][EXE] --bench`
+[RUNNING] `[..]target[/]release[/]deps[/]bench-[..][EXE] --bench`
[RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] --bench`", dir = p.url()))
.with_stdout("
running 1 test
[FRESH] bar v0.0.1 ({dir}/bar)
[FRESH] foo v0.0.1 ({dir})
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] `[..]target[/]release[/]bench-[..][EXE] --bench`
+[RUNNING] `[..]target[/]release[/]deps[/]bench-[..][EXE] --bench`
[RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] --bench`", dir = p.url()))
.with_stdout("
running 1 test
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
-[RUNNING] `{dir}[/]target[/]release[/]testb1-[..][EXE] --bench`
+[RUNNING] `{dir}[/]target[/]release[/]deps[/]testb1-[..][EXE] --bench`
[RUNNING] `{dir}[/]target[/]release[/]deps[/]testbench-[..][EXE] --bench`",
dir = p.root().display(), url = p.url()))
.with_stdout("
.with_stderr("\
[COMPILING] foo v0.1.0 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]b-[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]b-[..][EXE]")
.with_stdout("
running 1 test
test foo ... ok
#[no_mangle]
pub extern fn foo() {}
"#);
- assert_that(build.cargo_process("build"),
+ assert_that(build.cargo_process("build").arg("-v")
+ .env("RUST_LOG", "cargo::ops::cargo_rustc"),
execs().with_status(0));
let foo = project("foo")
}
"#);
- assert_that(foo.cargo_process("build").env("SRC", build.root()),
+ assert_that(foo.cargo_process("build").arg("-v").env("SRC", build.root())
+ .env("RUST_LOG", "cargo::ops::cargo_rustc"),
execs().with_status(0));
}
-C opt-level=3 \
-C lto \
-C metadata=[..] \
- --out-dir {dir}[/]target[/]release \
+ --out-dir {dir}[/]target[/]release[/]deps \
--emit=dep-info,link \
-L dependency={dir}[/]target[/]release[/]deps`
[FINISHED] release [optimized] target(s) in [..]
.unwrap();
assert_that(&p.bin("foo"), is_not(existing_file()));
+ // We expect a file of the form bin/foo-{metadata_hash}
assert_that(&p.bin("examples/foo"), existing_file());
p.cargo("test").arg("--no-run").arg("-v")
.unwrap();
assert_that(&p.bin("foo"), is_not(existing_file()));
+ // We expect a file of the form bin/foo-{metadata_hash}
assert_that(&p.bin("examples/foo"), existing_file());
}
assert_that(process(&p.bin("foo")),
execs().with_stdout("i am foo\n"));
- let d1_path = &p.build_dir().join("debug").join("deps")
+ let d1_path = &p.build_dir().join("debug")
.join(format!("d1{}", env::consts::EXE_SUFFIX));
- let d2_path = &p.build_dir().join("debug").join("deps")
+ let d2_path = &p.build_dir().join("debug")
.join(format!("d2{}", env::consts::EXE_SUFFIX));
assert_that(d1_path, existing_file());
.arg("-p").arg("foo"),
execs().with_status(0));
- let d1_path = &p.build_dir().join("debug").join("deps")
+ let d1_path = &p.build_dir().join("debug")
.join(format!("d1{}", env::consts::EXE_SUFFIX));
- let d2_path = &p.build_dir().join("debug").join("deps")
+ let d2_path = &p.build_dir().join("debug")
.join(format!("d2{}", env::consts::EXE_SUFFIX));
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc src[/]foo.rs --crate-name foo --crate-type bin -g \
-C metadata=[..] \
- --out-dir {dir}[/]target[/]{target}[/]debug \
+ --out-dir {dir}[/]target[/]{target}[/]debug[/]deps \
--emit=dep-info,link \
--target {target} \
-C ar=my-ar-tool -C linker=my-linker-tool \
.with_stderr(&format!("\
[COMPILING] foo v0.0.0 ({foo})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]{triple}[/]debug[/]bar-[..][EXE]
+[RUNNING] target[/]{triple}[/]debug[/]deps[/]bar-[..][EXE]
[RUNNING] target[/]{triple}[/]debug[/]deps[/]foo-[..][EXE]", foo = p.url(), triple = target))
.with_stdout("
running 1 test
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
- /* Targets should be cached from the first build */
+ /* Targets should be cached from the first build
+ XXX Sadly these cannot be cached since the "symlink" step is
+ not separate from the "compile" step. Packages which link
+ to top level binaries eg (deps/foo-abc123 -> foo) are forced
+ to do an extra recompile here.
+ */
assert_that(p.cargo("build"),
execs().with_status(0)
.with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
assert_that(p.cargo("build").arg("--features").arg("foo"),
execs().with_status(0)
.with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
"));
}
+#[test]
+fn changing_profiles_caches_targets() {
+ let p = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ authors = []
+ version = "0.0.1"
+
+ [profile.dev]
+ panic = "abort"
+
+ [profile.test]
+ panic = "unwind"
+ "#)
+ .file("src/lib.rs", "");
+
+ assert_that(p.cargo_process("build"),
+ execs().with_status(0)
+ .with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
+[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+"));
+
+ assert_that(p.cargo("test"),
+ execs().with_status(0)
+ .with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
+[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[..]debug[..]deps[..]foo-[..][EXE]
+[DOCTEST] foo
+"));
+
+ /* Targets should be cached from the first build
+ XXX Sadly these cannot be cached since the "symlink" step is
+ not separate from the "compile" step. Packages which link
+ to top level binaries eg (deps/foo-abc123 -> foo) are forced
+ to do an extra recompile here.
+ */
+
+ assert_that(p.cargo("build"),
+ execs().with_status(0)
+ .with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
+[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+"));
+
+ assert_that(p.cargo("test").arg("foo"),
+ execs().with_status(0)
+ .with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
+[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] target[..]debug[..]deps[..]foo-[..][EXE]
+[DOCTEST] foo
+"));
+}
+
#[test]
fn changing_bin_paths_common_target_features_caches_targets() {
- /// Make sure dep_cache crate is built once per feature
+ // Make sure dep_cache crate is built once per feature
let p = project("foo")
.file(".cargo/config", r#"
[build]
[..]Compiling dep_crate v0.0.1 ([..])
[..]Compiling a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/a`
+[RUNNING] `[..]target[/]debug[/]a[EXE]`
"));
assert_that(p.cargo("clean").arg("-p").arg("a").cwd(p.root().join("a")),
execs().with_status(0));
.with_stderr("\
[..]Compiling a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/a`
+[RUNNING] `[..]target[/]debug[/]a[EXE]`
"));
/* Build and rebuild b/. Ensure dep_crate only builds once */
[..]Compiling dep_crate v0.0.1 ([..])
[..]Compiling b v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/b`
+[RUNNING] `[..]target[/]debug[/]b[EXE]`
"));
assert_that(p.cargo("clean").arg("-p").arg("b").cwd(p.root().join("b")),
execs().with_status(0));
.with_stderr("\
[..]Compiling b v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/b`
+[RUNNING] `[..]target[/]debug[/]b[EXE]`
"));
/* Build a/ package again. If we cache different feature dep builds correctly,
.with_stderr("\
[..]Compiling a v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/a`
+[RUNNING] `[..]target[/]debug[/]a[EXE]`
"));
/* Build b/ package again. If we cache different feature dep builds correctly,
.with_stderr("\
[..]Compiling b v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target/debug/b`
+[RUNNING] `[..]target[/]debug[/]b[EXE]`
"));
}
[features]
foo = []
"#)
- .file("src/main.rs", "fn main() {}");
+ .file("src/main.rs", r#"
+ fn main() {
+ let msg = if cfg!(feature = "foo") { "feature on" } else { "feature off" };
+ println!("{}", msg);
+ }
+ "#);
- assert_that(p.cargo_process("build"),
+ assert_that(p.cargo_process("run"),
execs().with_status(0)
+ .with_stdout("feature off")
.with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]foo[EXE]`
"));
- assert_that(p.cargo("build").arg("--features").arg("foo"),
+ assert_that(p.cargo("run").arg("--features").arg("foo"),
execs().with_status(0)
+ .with_stdout("feature on")
.with_stderr("\
[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]foo[EXE]`
"));
- /* Targets should be cached from the first build */
+ /* Targets should be cached from the first build
+ XXX Sadly these cannot be cached since the "symlink" step is
+ not separate from the "compile" step. Packages which link
+ to top level binaries eg (deps/foo-abc123 -> foo) are forced
+ to do an extra recompile here.
+ */
- assert_that(p.cargo("build"),
+ assert_that(p.cargo("run"),
execs().with_status(0)
+ .with_stdout("feature off")
.with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]foo[EXE]`
"));
- assert_that(p.cargo("build"),
- execs().with_status(0)
- .with_stdout(""));
-
- assert_that(p.cargo("build").arg("--features").arg("foo"),
+ assert_that(p.cargo("run").arg("--features").arg("foo"),
execs().with_status(0)
+ .with_stdout("feature on")
.with_stderr("\
+[..]Compiling foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `target[/]debug[/]foo[EXE]`
"));
}
[COMPILING] [..] v0.5.0 ([..])
[COMPILING] [..] v0.5.0 ([..]
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]foo-[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]")
.with_stdout("
running 1 test
test tests::foo ... ok
[COMPILING] [..] v0.5.0 ([..])
[COMPILING] [..] v0.5.0 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]foo-[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]")
.with_stdout("
running 0 tests
fn main() {
let src = PathBuf::from(env::var("SRC").unwrap());
- println!("cargo:rustc-flags=-L {}/deps", src.parent().unwrap()
- .display());
+ println!("cargo:rustc-flags=-L {}/deps", src.parent().unwrap().display());
}
"#)
.file("bar/src/lib.rs", r#"
--out-dir {dir}[/]target[/]release[/]examples \
--emit=dep-info,link \
-L dependency={dir}[/]target[/]release[/]deps \
- --extern bar={dir}[/]target[/]release[/]deps[/]libbar.rlib`
+ --extern bar={dir}[/]target[/]release[/]deps[/]libbar-[..].rlib`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `target[/]release[/]examples[/]a[EXE]`
",
--out-dir {dir}[/]target[/]debug[/]examples \
--emit=dep-info,link \
-L dependency={dir}[/]target[/]debug[/]deps \
- --extern bar={dir}[/]target[/]debug[/]deps[/]libbar.rlib`
+ --extern bar={dir}[/]target[/]debug[/]deps[/]libbar-[..].rlib`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `target[/]debug[/]examples[/]a[EXE]`
",
--out-dir [..] \
--emit=dep-info,link \
-L dependency={dir}[/]target[/]debug[/]deps \
- --extern {name}={dir}[/]target[/]debug[/]deps[/]lib{name}.rlib`
+ --extern {name}={dir}[/]target[/]debug[/]deps[/]lib{name}-[..].rlib`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
",
dir = p.root().display(), url = p.url(),
execs().with_stderr(format!("\
[COMPILING] foo v0.5.0 ({})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]foo-[..][EXE]", p.url()))
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url()))
.with_stdout("
running 1 test
test test_hello ... ok
[RUNNING] [..] -C opt-level=3 [..]
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE]`
-[RUNNING] `[..]target[/]release[/]test-[..][EXE]`
+[RUNNING] `[..]target[/]release[/]deps[/]test-[..][EXE]`
[DOCTEST] foo
[RUNNING] `rustdoc --test [..]lib.rs[..]`", dir = p.url()))
.with_stdout("
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc src[/]foo.rs [..]`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] `[..]target[/]debug[/]foo-[..][EXE] hello`", url = p.url()))
+[RUNNING] `[..]target[/]debug[/]deps[/]foo-[..][EXE] hello`", url = p.url()))
.with_stdout("
running 1 test
test test_hello ... ok
execs().with_stderr(format!("\
[COMPILING] foo v0.5.0 ({url})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]foo-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
[ERROR] test failed", url = p.url()))
.with_stdout_contains("
running 1 test
execs().with_stderr(format!("\
[COMPILING] foo v0.0.1 ({})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]baz-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]baz-[..][EXE]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
[DOCTEST] foo", p.url()))
.with_stdout("
[COMPILING] foo v0.0.1 ({})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]debug[/]test-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]
[DOCTEST] foo", p.url()))
.with_stdout("
running 1 test
execs().with_stderr(format!("\
[COMPILING] foo v0.0.1 ({})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]external-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]external-[..][EXE]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
[DOCTEST] foo", p.url()))
.with_stdout("
[COMPILING] foo v0.0.1 ({})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]debug[/]foo-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
[DOCTEST] foo", p.url()))
.with_stdout("
running 1 test
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE]
-[RUNNING] target[/]debug[/]test-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]
[DOCTEST] syntax", dir = p.url()))
.with_stdout("
running 1 test
.with_stderr(&format!("\
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]syntax-[..][EXE]", dir = p.url()))
+[RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE]", dir = p.url()))
.with_stdout("
running 1 test
test test ... ok
.with_stderr(&format!("\
[COMPILING] syntax v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]syntax-[..][EXE]", dir = p.url()))
+[RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE]", dir = p.url()))
.with_stdout("
running 1 test
test test ... ok
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]debug[/]test-[..][EXE]", dir = p.url()))
+[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]", dir = p.url()))
.with_stdout("
running 1 test
test foo ... ok
.with_stderr("\
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]debug[/]test-[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]")
.with_stdout("
running 1 test
test foo ... ok
.with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]bin2-[..][EXE]", dir = prj.url()))
+[RUNNING] target[/]debug[/]deps[/]bin2-[..][EXE]", dir = prj.url()))
.with_stdout("
running 1 test
test test2 ... ok
.with_stderr(format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]b-[..][EXE]", dir = prj.url()))
+[RUNNING] target[/]debug[/]deps[/]b-[..][EXE]", dir = prj.url()))
.with_stdout("
running 1 test
test test_b ... ok
.with_stderr(&format!("\
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]bar-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]bar-[..][EXE]
",
dir = p.url())));
}
execs().with_stderr("\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-[RUNNING] target[/]debug[/]foo[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]foo[..][EXE]")
.with_stdout("
running 0 tests
[COMPILING] foo v0.0.1 ([..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]
-[RUNNING] target[/]debug[/]test_add_one-[..][EXE]")
+[RUNNING] target[/]debug[/]deps[/]test_add_one-[..][EXE]")
.with_stdout_contains("
running 0 tests
")
.with_stderr_contains("\
-[RUNNING] target[/]debug[/]test_sub_one-[..][EXE]
+[RUNNING] target[/]debug[/]deps[/]test_sub_one-[..][EXE]
[DOCTEST] foo")
.with_stdout_contains("\
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured